package com.wondertek.common.util.security;

import cn.hutool.http.HttpStatus;
import com.wondertek.common.exception.AppException;
import jakarta.annotation.Resource;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

/**
 * @author: gongjiangtao
 * @date: 2024/8/25 10:22
 * @Description: 权限校验
 * @Version: 1.0
 */
@Aspect
@Component
public class AuthorizationAspect {

    @Resource
    private ElPermissionConfig el;

    private final ExpressionParser parser = new SpelExpressionParser();

    @Resource
    private BeanFactory beanFactory; // 注入 BeanFactory

    @Before("@annotation(com.wondertek.common.util.security.PreAuthorize)")
    public void checkAuthorization(JoinPoint joinPoint) {
        // 获取方法上的 @CheckPermission 注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        PreAuthorize preAuthorize = AnnotationUtils.findAnnotation(signature.getMethod(), PreAuthorize.class);

        if (preAuthorize != null) {
            // 解析注解中的表达式
            String expression = preAuthorize.value();

            // 创建SpEL上下文并添加el服务
            StandardEvaluationContext context = new MethodBasedEvaluationContext(null, signature.getMethod(), joinPoint.getArgs(), null);
            context.setBeanResolver(new BeanFactoryResolver(beanFactory));

            Boolean result = parser.parseExpression(expression).getValue(context, Boolean.class);

            // 如果权限不足，抛出异常
            if (Boolean.FALSE.equals(result)) {
                throw new AppException(HttpStatus.HTTP_FORBIDDEN,"authority.error");
            }
        }
    }
}
